/* 
 * File:   CalendarRenderer.c
 * Author: Muqtafi Akhmad
 */
#include "CalendarRenderer.h"

/**
 * Creates a calendar renderer
 * @param calendar referenced calendar 
 * @return calendar renderer
 */
CalendarRenderer CreateCalendarRenderer(Calendar *calendar) {
    CalendarRenderer renderer;
    int i, j;
    renderer.calendar = calendar;
    renderer.currentMonth = 1;
    renderer.currentYear = BASE_YEAR;
    return renderer;
}

/**
 * Returs reference to calendar
 * @param renderer calendar renderer
 * @return reference to calendar
 */
Calendar* GetCalendar(CalendarRenderer renderer) {
    return renderer.calendar;
}

/**
 * Returns current month of renderer
 * @param renderer renderer
 * @return current month
 */
int GetCurrentMonth(CalendarRenderer renderer) {
    return renderer.currentMonth;
}

/**
 * Returns current year of renderer
 * @param renderer renderer
 * @return current year
 */
int GetCurrentYear(CalendarRenderer renderer) {
    return renderer.currentYear;
}

/**
 * Set calendar of renderer
 * @param renderer renderer
 * @param calendar calendar
 */
void SetCalendar(CalendarRenderer* renderer, Calendar *calendar) {
    renderer->calendar = calendar;
}

/**
 * Set current month of renderer
 * @param renderer renderer
 * @param month current month
 */
void SetCurrentMonth(CalendarRenderer *renderer, int month) {
    renderer->currentMonth = month;
}

/**
 * Set current year of renderer
 * @param renderer renderer
 * @param year current year
 */
void SetCurrentYear(CalendarRenderer *renderer, int year) {
    renderer->currentYear = year;
}

/**
 * Move current month to next month
 * @param renderer renderer
 */
void AdvanceMonth(CalendarRenderer *renderer) {
    renderer->currentMonth++;
    if (renderer->currentMonth == 13) {
        renderer->currentMonth = 1;
        renderer->currentYear++;
    }
}

/**
 * Move current month to previous month
 * @param renderer
 */
void BackMonth(CalendarRenderer *renderer) {
    renderer->currentMonth--;
    if (renderer->currentMonth == 0) {
        renderer->currentMonth = 12;
        renderer->currentYear--;
    }
}

/**
 * Render the calendar for the current month and year
 * @param renderer
 */
void RenderCalendar(CalendarRenderer renderer) {
    int iter, dayIter, dayMax = MaxDaysInMonth(renderer.currentMonth, renderer.currentYear);
    Day dayHeader = Ahad;
    Day currDay = GetFirstDay(renderer.currentYear, renderer.currentMonth);
    currDay %= 7;
    long entryNoBuff[100];
    // print header
#ifdef _WIN32
    system("cls");
#endif
    printf("Month %02i, Year %04i", renderer.currentMonth, renderer.currentYear);
    EndLine();
#ifdef _WIN32
    printf("Press '%c' to next month, '%c' to previous month, and ESC to exit", RIGHT_KEY, LEFT_KEY);
#endif
    EndLine();
    // end of print header, start of print first row
    EndLine();
    PrintHLine();
    EndLine();
    printf("%c", V_STRIP);
    for (iter = 0; iter < DAY_IN_WEEK_MAX; iter++) {
        printf("%s%c", GetDayString(dayHeader), V_STRIP); // print day
        dayHeader++;
    }
    EndLine();
    PrintHLine();
    // end of print first row
    EndLine();
    printf("%c", V_STRIP);
    for (iter = 0; iter < currDay; iter++) {
        printf("      %c", V_STRIP); // start filler
    }
    for (dayIter = 1; dayIter <= dayMax; dayIter++) {
        int eventCount = GetEventCountInDay(renderer.calendar->events, MakeDateTime(renderer.currentYear, renderer.currentMonth, dayIter, 0, 0, 0), entryNoBuff, 100);
        if (eventCount > 0) {
            printf("%02i.%03i%c", dayIter, eventCount, V_STRIP); // prints count of event
        } else {
            printf("%02i.   %c", dayIter, V_STRIP); // prints nothing if there is no event
        }
        currDay++;
        if (currDay == DAY_IN_WEEK_MAX) {
            currDay -= DAY_IN_WEEK_MAX; // reset day 
            EndLine();
            PrintHLine(); // print new horizontal line
            EndLine();
            if (dayIter < dayMax) {
                printf("%c", V_STRIP);
            }
        }
    }
    if (currDay != Ahad) {
        for (iter = currDay; iter < DAY_IN_WEEK_MAX; iter++) {
            printf("      %c", V_STRIP); // end filler
        }
        EndLine();
        PrintHLine();
    }
    EndLine();
}

/**
 * Print end line
 */
void EndLine() {
    printf("\n");
}

/**
 * Print horizontal line
 */
void PrintHLine() {
    int iter;
    printf("%c", H_STRIP);
    for (iter = 0; iter < DAY_IN_WEEK_MAX; iter++) {
        printf("%s", H_CELL);
    }
}

/**
 * Show events count in a month as table
 * @param calendar the calendar
 * @param args year and month of calendar
 */
void ShowCalendar(Calendar* calendar, char**args) {
    if (args[1] && args[2]) {
        if (EventListEmpty(calendar->events)) {
            printf("The calendar is empty\n");
        } else {
            char readChar;
            CalendarRenderer renderer;
            SetCalendar(&renderer, calendar);
            renderer.currentYear = atoi(args[1]); // set year
            renderer.currentMonth = atoi(args[2]); // set month
#ifdef _WIN32
            do {
#endif
                RenderCalendar(renderer); // print calendar
#ifdef _WIN32
                readChar = getch();
                if (readChar == RIGHT_KEY)
                    AdvanceMonth(&renderer);
                else if (readChar == LEFT_KEY)
                    BackMonth(&renderer);
            } while (readChar != ESC_KEY);
#endif
        }
    }
}
